home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / FLTK-1.0.6 / src / Fl_Input.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-20  |  10.1 KB  |  342 lines

  1. //
  2. // "$Id: Fl_Input.cxx,v 1.10.2.1 1999/04/20 04:43:24 bill Exp $"
  3. //
  4. // Input widget for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-1999 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems to "fltk-bugs@easysw.com".
  24. //
  25.  
  26. // This is the "user interface", it decodes user actions into what to
  27. // do to the text.  See also Fl_Input_.C, where the text is actually
  28. // manipulated (and some ui, in particular the mouse, is done...).
  29. // In theory you can replace this code with another subclass to change
  30. // the keybindings.
  31.  
  32. #include <FL/Fl.H>
  33. #include <FL/Fl_Input.H>
  34. #include <FL/fl_draw.H>
  35. #include <math.h>
  36. #include <string.h>
  37. #include <ctype.h>
  38.  
  39. void Fl_Input::draw() {
  40.   if (type() == FL_HIDDEN_INPUT) return;
  41.   Fl_Boxtype b = box();
  42.   if (damage() & FL_DAMAGE_ALL) draw_box(b, color());
  43.   Fl_Input_::drawtext(x()+Fl::box_dx(b)+3, y()+Fl::box_dy(b),
  44.               w()-Fl::box_dw(b)-6, h()-Fl::box_dh(b));
  45. }
  46.  
  47. // kludge so shift causes selection to extend:
  48. int Fl_Input::shift_position(int p) {
  49.   return position(p, Fl::event_state(FL_SHIFT) ? mark() : p);
  50. }
  51. int Fl_Input::shift_up_down_position(int p) {
  52.   return up_down_position(p, Fl::event_state(FL_SHIFT));
  53. }
  54.  
  55. ////////////////////////////////////////////////////////////////
  56. // Fltk "compose"
  57. //
  58. // This is a demonstration of a IMHO "correct" interface to compose
  59. // character sequences.  It does not have a "dead key" effect: the
  60. // user has feedback at all times, and sees exactly the symbol they
  61. // will get if they stop typing at that point.  Notice that I totally
  62. // ignore the horrid XIM extension!
  63. //
  64. // You only need to keep track of your normal text buffer and a
  65. // single integer "state".  Call fl_compose() for each character
  66. // keystroke.  The return value is the new "state" that must be passed
  67. // the next time you call fl_compose().  It also returns the number of
  68. // characters to delete to the left, a buffer of new characters, and
  69. // the number of characters in that buffer.  Obey these editing
  70. // instructions.  Reset the state to zero if the user types any
  71. // function keys or clicks the mouse.
  72. //
  73. // Fl_Input does not call fl_compose unless you hit the "compose" key
  74. // first.  It may be interesting and useful to always call it, though...
  75.  
  76. // Although this simple code is only for ISO-8859-1 character
  77. // encodings, I think the interface can be expanded to UTF-8 (encoded
  78. // Unicode) someday.
  79.  
  80. // This string lists a pair for each possible foreign letter in ISO-8859-1
  81. // starting at code 0xa0 (nbsp).  If the second character is a space then
  82. // only the first character needs to by typed:
  83. static const char* const compose_pairs =
  84. "  ! % # $ y=| & : c a <<~ - r _ * +-2 3 ' u p . , 1 o >>141234? "
  85. "A`A'A^A~A:A*AEC,E`E'E^E:I`I'I^I:D-N~O`O'O^O~O:x O/U`U'U^U:Y'THss"
  86. "a`a'a^a~a:a*aec,e`e'e^e:i`i'i^i:d-n~o`o'o^o~o:-:o/u`u'u^u:y'thy:";
  87.  
  88. int fl_compose(int state, char c, int& del, char* buffer, int& ins) {
  89.   del = 0; ins = 1; buffer[0] = c;
  90.  
  91.   if (c == '"') c = ':';
  92.  
  93.   if (!state) {    // first character
  94.     if (c == ' ') {buffer[0]=char(0xA0);return 0x100;} // space turns into nbsp
  95.     // see if it is either character of any pair:
  96.     state = 0;
  97.     for (const char *p = compose_pairs; *p; p += 2) 
  98.       if (p[0] == c || p[1] == c) {
  99.     if (p[1] == ' ') buffer[0] = (p-compose_pairs)/2+0xA0;
  100.     state = c;
  101.       }
  102.     return state;
  103.  
  104.   } else if (state == 0x100) { // third character
  105.     return 0;
  106.  
  107.   } else { // second character
  108.     char c1 = char(state); // first character
  109.     // now search for the pair in either order:
  110.     for (const char *p = compose_pairs; *p; p += 2) {
  111.       if (p[0] == c && p[1] == c1 || p[1] == c && p[0] == c1) {
  112.     buffer[0] = (p-compose_pairs)/2+0xA0;
  113.     ins = del = 1;
  114.     return 0x100;
  115.       }
  116.     }
  117.     return 0;
  118.   }
  119. }
  120.  
  121. ////////////////////////////////////////////////////////////////
  122.  
  123. static int compose; // compose state (# of characters so far + 1)
  124.  
  125. // If you define this symbol as zero you will get the peculiar fltk
  126. // behavior where moving off the end of an input field will move the
  127. // cursor into the next field:
  128. // define it as 1 to prevent cursor movement from going to next field:
  129. #define NORMAL_INPUT_MOVE 0
  130.  
  131. #define ctrl(x) (x^0x40)
  132.  
  133. int Fl_Input::handle_key() {
  134.   int i;
  135.  
  136.   int pcompose = compose; compose = 0;
  137.   char key = Fl::event_text()[0];
  138.  
  139.   if (pcompose && Fl::event_length()) {
  140.     char buf[20]; int ins; int del;
  141.     compose = fl_compose(pcompose-1, key, del, buf, ins);
  142.     if (compose) {
  143.       replace(position(), del ? position()-del : mark(), buf, ins);
  144.       compose++; // store value+1 so 1 can initialize compose state
  145.       return 1;
  146.     } else {
  147.       if (pcompose==1)    // compose also acts as quote-next:
  148.     return replace(position(),mark(),Fl::event_text(),Fl::event_length());
  149.     }
  150.   }
  151.  
  152.   if (Fl::event_state(FL_ALT|FL_META)) { // reserved for shortcuts
  153.     compose = pcompose;
  154.     return 0;
  155.   }
  156.  
  157.   switch (Fl::event_key()) {
  158.   case FL_Left:
  159.     key = ctrl('B'); break;
  160.   case FL_Right:
  161.     key = ctrl('F'); break;
  162.   case FL_Up:
  163.     key = ctrl('P'); break;
  164.   case FL_Down:
  165.     key = ctrl('N'); break;
  166.   case FL_Delete:
  167.     key = ctrl('D'); break;
  168.   case FL_Home:
  169.     key = ctrl('A'); break;
  170.   case FL_End:
  171.     key = ctrl('E'); break;
  172.   case FL_BackSpace:
  173.     if (mark() != position()) cut();
  174.     else cut(-1);
  175.     return 1;
  176.   case FL_Enter:
  177.   case FL_KP_Enter:
  178.     if (when() & FL_WHEN_ENTER_KEY) {
  179.       position(size(), 0);
  180.       maybe_do_callback();
  181.       return 1;
  182.     } else if (type() == FL_MULTILINE_INPUT)
  183.       return replace(position(), mark(), "\n", 1);
  184.     else 
  185.       return 0;    // reserved for shortcuts
  186.   case FL_Tab:
  187.     if (Fl::event_state(FL_CTRL) || type()!=FL_MULTILINE_INPUT) return 0;
  188.     break;
  189.   case FL_Escape:
  190.     return 0;    // reserved for shortcuts (Forms cleared field)
  191.   case FL_Control_R:
  192.   case 0xff20: // Multi-Key
  193.     compose = 1;
  194.     return 1;
  195.   }
  196.  
  197.   switch(key) {
  198.   case 0:    // key did not translate to any text
  199.     compose = pcompose; // allow user to hit shift keys after ^Q
  200.     return 0;
  201.   case ctrl('A'):
  202.     if (type() == FL_MULTILINE_INPUT)
  203.       for (i=position(); i && index(i-1)!='\n'; i--) ;
  204.     else
  205.       i = 0;
  206.     return shift_position(i) + NORMAL_INPUT_MOVE;
  207.   case ctrl('B'):
  208.     return shift_position(position()-1) + NORMAL_INPUT_MOVE;
  209.   case ctrl('C'): // copy
  210.     return copy();
  211.   case ctrl('D'):
  212.     if (mark() != position()) return cut();
  213.     else return cut(1);
  214.   case ctrl('E'):
  215.     if (type() == FL_MULTILINE_INPUT)
  216.       for (i=position(); index(i) && index(i)!='\n'; i++) ;
  217.     else
  218.       i = size();
  219.     return shift_position(i) + NORMAL_INPUT_MOVE;
  220.   case ctrl('F'):
  221.     return shift_position(position()+1) + NORMAL_INPUT_MOVE;
  222.   case ctrl('K'):
  223.     if (position()>=size()) return 0;
  224.     if (type() == FL_MULTILINE_INPUT) {
  225.       if (index(position()) == '\n')
  226.     i = position() + 1;
  227.       else 
  228.     for (i=position()+1; index(i) && index(i) != '\n'; i++);
  229.     } else
  230.       i = size();
  231.     cut(position(), i);
  232.     return copy_cuts();
  233.   case ctrl('N'):
  234.     if (type()!=FL_MULTILINE_INPUT) return 0;
  235.     for (i=position(); index(i)!='\n'; i++)
  236.       if (!index(i)) return NORMAL_INPUT_MOVE;
  237.     shift_up_down_position(i+1);
  238.     return 1;
  239.   case ctrl('P'):
  240.     if (type()!=FL_MULTILINE_INPUT) return 0;
  241.     for (i = position(); i > 0 && index(i-1) != '\n'; i--) ;
  242.     if (!i) return NORMAL_INPUT_MOVE;
  243.     shift_up_down_position(i-1);
  244.     return 1;
  245.   case ctrl('Q'):
  246.     compose = 1;
  247.     return 1;
  248.   case ctrl('U'):
  249.     return cut(0, size());
  250.   case ctrl('V'):
  251.   case ctrl('Y'):
  252.     Fl::paste(*this);
  253.     return 1;
  254.   case ctrl('X'):
  255.   case ctrl('W'):
  256.     copy();
  257.     return cut();
  258.   case ctrl('Z'):
  259.   case ctrl('_'):
  260.     return undo();
  261.   }
  262.  
  263.   // skip all illegal characters
  264.   // this could be improved to make sure characters are inserted at
  265.   // legal positions...
  266.   if (type() == FL_FLOAT_INPUT) {
  267.     if (!strchr("0123456789.eE+-", key)) return 0;
  268.   } else if (type() == FL_INT_INPUT) {
  269.     if (!position() && (key == '+' || key == '-'));
  270.     else if (key >= '0' && key <= '9');
  271.     // we allow 0xabc style hex numbers to be typed:
  272.     else if (position()==1 && index(0)=='0' && (key == 'x' || key == 'X'));
  273.     else if (position()>1 && index(0)=='0' && (index(1)=='x'||index(1)=='X')
  274.            && (key>='A'&& key<='F' || key>='a'&& key<='f'));
  275.     else return 0;
  276.   }
  277.  
  278.   return replace(position(), mark(), Fl::event_text(), Fl::event_length());
  279. }
  280.  
  281. int Fl_Input::handle(int event) {
  282.   switch (event) {
  283.  
  284.   case FL_FOCUS:
  285.     switch (Fl::event_key()) {
  286.     case FL_Right:
  287.       position(0);
  288.       break;
  289.     case FL_Left:
  290.       position(size());
  291.       break;
  292.     case FL_Down:
  293.       up_down_position(0);
  294.       break;
  295.     case FL_Up:
  296.       up_down_position(size());
  297.       break;
  298.     case FL_Tab:
  299.     case 0xfe20: // XK_ISO_Left_Tab
  300.       position(size(),0);
  301.       break;
  302.     }
  303.     break;
  304.  
  305.   case FL_UNFOCUS:
  306.     compose = 0;
  307.     break;
  308.  
  309.   case FL_KEYBOARD:
  310.     return handle_key();
  311.  
  312.   case FL_PUSH:
  313.     compose = 0;
  314.     if (Fl::event_button() == 2) {
  315.       Fl::paste(*this);
  316.       if (Fl::focus()==this) return 1; // remove line for Motif behavior
  317.     }
  318.     if (Fl::focus() != this) {
  319.       Fl::focus(this);
  320.       handle(FL_FOCUS); // cause minimal update
  321.     }
  322.     break;
  323.  
  324.   case FL_DRAG:
  325.   case FL_RELEASE:
  326.     if (Fl::event_button() == 2) return 0;
  327.     break;
  328.   }
  329.   Fl_Boxtype b = box();
  330.   return Fl_Input_::handletext(event,
  331.     x()+Fl::box_dx(b)+3, y()+Fl::box_dy(b),
  332.     w()-Fl::box_dw(b)-6, h()-Fl::box_dh(b));
  333. }
  334.  
  335. Fl_Input::Fl_Input(int x, int y, int w, int h, const char *l)
  336. : Fl_Input_(x, y, w, h, l) {
  337. }
  338.  
  339. //
  340. // End of "$Id: Fl_Input.cxx,v 1.10.2.1 1999/04/20 04:43:24 bill Exp $".
  341. //
  342.